﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows;
using System.Windows.Media.Imaging;
using System.Windows.Media.Animation;

namespace ASoft.WPF
{
    public class AnimatedImage : Image
    {
        static AnimatedImage()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(AnimatedImage), new FrameworkPropertyMetadata(typeof(AnimatedImage)));
        }

        public int FrameIndex
        {
            get { return (int)GetValue(FrameIndexProperty); }
            set { SetValue(FrameIndexProperty, value); }
        }

        public RepeatBehavior AnimationRepeatBehavior
        {
            get { return (RepeatBehavior)GetValue(AnimationRepeatBehaviorProperty); }
            set { SetValue(AnimationRepeatBehaviorProperty, value); }
        }

        public AnimatedImageSource AnimatedSource
        {
            get { return (AnimatedImageSource)GetValue(AnimatedSourceProperty); }
            set { SetValue(AnimatedSourceProperty, value); }
        }

        public void OnAnimatedSourceChanged(DependencyPropertyChangedEventArgs e)
        {
            BeginAnimation(FrameIndexProperty, null);
            if (this.AnimatedSource == null || this.AnimatedSource.Frames.Count == 0)
            {
                this.FrameIndex = -1;
                return;
            }
            this.FrameIndex = this.FrameIndex < 0 ? 0 : this.FrameIndex;
            base.Source = this.AnimatedSource.Frames[FrameIndex];
        }


        Int32Animation GetInt32Animation()
        {
            return GetInt32Animation(null);
        }

        Int32Animation GetInt32Animation(RepeatBehavior? repeatBehavior)
        {
            if (AnimatedSource == null)
            {
                return null;
            }
            var second = ((int)(AnimationSecond < 1 ? 10 : AnimationSecond)
                * (IsDesc ? FrameIndex : (AnimatedSource.Frames.Count - FrameIndex))
                / AnimatedSource.Frames.Count);
            second = second < 1 ? 1 : second;

            var startIndex = this.FrameIndex;
            var endIndex = AnimatedSource.Frames.Count - 1;

            if (IsDesc)
                endIndex = 0;

            var result = new Int32Animation(
                     startIndex,
                     endIndex,
                     new Duration(
                         new TimeSpan(
                             0,
                             0,
                             0,
                             second,
                             0)));
            if (repeatBehavior != null)
            {
                result.RepeatBehavior = repeatBehavior.Value;
            }

            return result;
        }

        public void Repeat()
        {
            GoZero();
            BeginAnimation(FrameIndexProperty, GetInt32Animation(RepeatBehavior.Forever));
        }

        public void GoZero()
        {
            BeginAnimation(FrameIndexProperty, null);
            FrameIndex = 0;
        }

        public void Pause()
        {
            int index = FrameIndex;
            BeginAnimation(FrameIndexProperty, null);
            FrameIndex = index;
        }

        public void RunOne()
        {
            GoZero();
            BeginAnimation(FrameIndexProperty, GetInt32Animation());
        }

        public void Continue()
        {
            BeginAnimation(FrameIndexProperty, GetInt32Animation());
        }

        public void Clear()
        {
            BeginAnimation(FrameIndexProperty, null);
            FrameIndex = 0;
            Source = null;
        }

        /// <summary>
        /// 正向还是反向播放动画
        /// </summary>
        public bool IsDesc { get; set; }


        /// <summary>
        /// 动画完全秒数
        /// </summary>
        public int AnimationSecond { get; set; }

        private static void ChangingFrameIndex
            (DependencyObject dp, DependencyPropertyChangedEventArgs e)
        {
            AnimatedImage animatedImage = dp as AnimatedImage;

            if (animatedImage == null || animatedImage.AnimatedSource == null)
            {
                return;
            }

            int frameIndex = (int)e.NewValue;
            ((Image)animatedImage).Source = animatedImage.AnimatedSource.Frames[frameIndex];
            animatedImage.InvalidateVisual();

            //if (frameIndex == animatedImage.AnimatedSource.Frames.Count - 1)
            //{
            //    animatedImage.BeginAnimation(FrameIndexProperty, null);
            //    animatedImage.FrameIndex = frameIndex;
            //}
        }

        private static void OnAnimatedSourceChanged
            (DependencyObject dp, DependencyPropertyChangedEventArgs e)
        {
            ((AnimatedImage)dp).OnAnimatedSourceChanged(e);
        }

        public static readonly DependencyProperty FrameIndexProperty =
            DependencyProperty.Register(
                "FrameIndex",
                typeof(int),
                typeof(AnimatedImage),
                new UIPropertyMetadata(0, ChangingFrameIndex));

        public static readonly DependencyProperty AnimatedSourceProperty =
            DependencyProperty.Register(
                "AnimatedSource",
                typeof(AnimatedImageSource),
                typeof(AnimatedImage),
                new FrameworkPropertyMetadata(
                    null,
                    FrameworkPropertyMetadataOptions.AffectsRender |
                    FrameworkPropertyMetadataOptions.AffectsMeasure,
                    OnAnimatedSourceChanged));

        public static readonly DependencyProperty AnimationRepeatBehaviorProperty =
            DependencyProperty.Register(
            "AnimationRepeatBehavior",
            typeof(RepeatBehavior),
            typeof(AnimatedImage),
            new PropertyMetadata(null));
    }
}
